package com.game.battle.common.math;

import com.game.battle.common.map.MyRenderGrid;

public class ColidTest {
	
	public static boolean testSegment2Box2(Segment2 segment, Box2 box)
	{
		Vector2 diff = Vector2.sub(segment.center, box.center);
		float RHS;

		float AWdU0 = Math.abs(segment.direction.dot(box.axis0));
		float ADdU0 = Math.abs(diff.dot(box.axis0));
		RHS         = box.extents.x + segment.extent * AWdU0;
		if (ADdU0 > RHS)
		{
			return false;
		}

		float AWdU1 = Math.abs(segment.direction.dot(box.axis1));
		float ADdU1 = Math.abs(diff.dot(box.axis1));
		RHS         = box.extents.y + segment.extent * AWdU1;
		if (ADdU1 > RHS)
		{
			return false;
		}

		Vector2 perp = segment.direction.perp();

		float LHS   = Math.abs(perp.dot(diff));
		float part0 = Math.abs(perp.dot(box.axis0));
		float part1 = Math.abs(perp.dot(box.axis1));
		RHS         = box.extents.x * part0 + box.extents.y * part1;

		return LHS <= RHS;
	}
	
	
	public static boolean testSegment2Circle2(Segment2 segment, Circle2 circle)
	{
		Vector2 delta = Vector2.sub(segment.center, circle.center);
		float a0 = delta.sqrMagnitude() - circle.radius * circle.radius;

		if (a0 <= Mathfex.ZeroTolerance)
		{
			// P is inside or on the sphere.
			return true;
		}
		// Else: P is outside the sphere.

		float a1 = Vector2.dot(segment.direction, delta);
		float discr = a1 * a1 - a0;
		if (discr < -Mathfex.ZeroTolerance)
		{
			// two complex-valued roots, no intersections
			return false;
		}

		float absA1 = Math.abs(a1);
		float qval = segment.extent * (segment.extent - 2 * absA1) + a0;
		return qval <= Mathfex.ZeroTolerance || absA1 <= segment.extent;
	}
	
	
	public static boolean testBox2Circle2(Box2 box, Circle2 circle)
	{
		float distSquared = 0f;
		float delta;
		float proj;
		float extent;

		Vector2 diff = Vector2.sub(circle.center, box.center);

		proj = diff.dot(box.axis0);
		extent = box.extents.x;
		if (proj < -extent)
		{
			delta = proj + extent;
			distSquared += delta * delta;
		}
		else if (proj > extent)
		{
			delta = proj - extent;
			distSquared += delta * delta;
		}

		proj = diff.dot(box.axis1);
		extent = box.extents.y;
		if (proj < -extent)
		{
			delta = proj + extent;
			distSquared += delta * delta;
		}
		else if (proj > extent)
		{
			delta = proj - extent;
			distSquared += delta * delta;
		}

		return distSquared <= circle.radius * circle.radius;
	}
	
	
	
	public static boolean testBox2Box2(Box2 box0, Box2 box1)
	{
		Vector2 A0 = box0.axis0;
		Vector2 A1 = box0.axis1;
		Vector2 B0 = box1.axis0;
		Vector2 B1 = box1.axis1;

		float EA0 = box0.extents.x;
		float EA1 = box0.extents.y;
		float EB0 = box1.extents.x;
		float EB1 = box1.extents.y;

		// Compute difference of box centers, D = C1-C0.
		Vector2 D = Vector2.sub(box1.center, box0.center);

		float AbsAdB00, AbsAdB01, AbsAdB10, AbsAdB11;
		float AbsAdD, RSum;

		
		// axis C0+t*A0
		AbsAdB00 = Math.abs(A0.dot(B0));
		AbsAdB01 = Math.abs(A0.dot(B1));
		AbsAdD   = Math.abs(A0.dot(D));
		RSum     = EA0 + EB0 * AbsAdB00 + EB1 * AbsAdB01;
		if (AbsAdD > RSum)
		{
			return false;
		}

		// axis C0+t*A1
		AbsAdB10 = Math.abs(A1.dot(B0));
		AbsAdB11 = Math.abs(A1.dot(B1));
		AbsAdD   = Math.abs(A1.dot(D));
		RSum     = EA1 + EB0 * AbsAdB10 + EB1 * AbsAdB11;
		if (AbsAdD > RSum)
		{
			return false;
		}


		// axis C0+t*B0
		AbsAdD = Math.abs(B0.dot(D));
		RSum   = EB0 + EA0 * AbsAdB00 + EA1 * AbsAdB10;
		if (AbsAdD > RSum)
		{
			return false;
		}

		// axis C0+t*B1
		AbsAdD = Math.abs(B1.dot(D));
		RSum   = EB1 + EA0 * AbsAdB01 + EA1 * AbsAdB11;
		if (AbsAdD > RSum)
		{
			return false;
		}

		return true;
	}
	
	 public static Vector2 rotateVectorByXZ(Vector2 v, float degrees)
	    {
	        float degToRad = (float)(Math.PI) / 180f;
	        float radians = degrees * degToRad;

	        float ca = (float)Math.cos(radians);
	        float sa = (float)Math.sin(radians);
	        return new Vector2(ca * v.x - sa * v.y, sa * v.x + ca * v.y);    
	    }
	
	 public static boolean isCheckRectInArcRange(MyRenderGrid grid, float Width, float Range, Vector2 casterPos,Vector2 defencePos)
	    {
	        Vector2 tRectA = grid.rect.rectA;
	        Vector2 tRectB = grid.rect.rectB;
	        Vector2 tRectC = grid.rect.rectC;
	        Vector2 tRectD = grid.rect.rectD;


	        Vector2 arcLine1 = rotateVectorByXZ(Vector2.normalize(Vector2.sub(defencePos, casterPos)), -Width / 2);
	        Vector2 arcLine2 = rotateVectorByXZ(Vector2.normalize(Vector2.sub(defencePos, casterPos)), Width / 2);

	        if (checkArcBoundsPoint(casterPos, tRectA, Range, Vector2.normalize(Vector2.sub(defencePos, casterPos)), Width))
	        {
	            return true;
	        }

	        if (checkArcBoundsPoint(casterPos, tRectB, Range, Vector2.normalize(Vector2.sub(defencePos, casterPos)), Width))
	        {
	            return true;
	        }

	        if (checkArcBoundsPoint(casterPos, tRectC, Range, Vector2.normalize(Vector2.sub(defencePos, casterPos)), Width))
	        {
	            return true;
	        }

	        if (checkArcBoundsPoint(casterPos, tRectD, Range, Vector2.normalize(Vector2.sub(defencePos, casterPos)), Width))
	        {
	            return true;
	        }

	        // arcline1
	        Vector2 arcLine1End = Vector2.add(casterPos, Vector2.multi(arcLine1, Range));
	        Segment2 segment1 = new Segment2(new Vector2(casterPos.x, casterPos.y), new Vector2(arcLine1End.x, arcLine1End.y));

	        // arcline2
	        Vector2 arcLine2End = Vector2.add(casterPos, Vector2.multi(arcLine2, Range));
	        Segment2 segment2 = new Segment2(new Vector2(casterPos.x, casterPos.y), new Vector2(arcLine2End.x, arcLine2End.y));

	        // 两边任意一边圆相交
	        if(testSegment2Box2(segment1, grid.gridBox2) ||
	            testSegment2Box2(segment2, grid.gridBox2))
	        {
	            return true;
	        }
	        return false;
	    }
	 
	 
	  public static boolean checkArcBoundsPoint(Vector2 casterPos, Vector2 point, float radius, Vector2 forward, float ArcWidth)
	    {
	        Vector2 dir = Vector2.sub(point, casterPos);

	        if (dir.getMagnitude() > radius)
	        {
	            return false;
	        }

	        if (Vector2.angle(Vector2.normalize(dir), forward) > (ArcWidth / 2))
	        {
	            return false;
	        }

	        return true;
	    }
}
